#include "widget_scene_tree.h"
#include "ui_widget_scene_tree.h"
#include "../AvatarLibrary.h"
#include "../utility/SceneExport.h"
#include "../utility/ProjectReader.h"
#include <QPushButton>
#include <QStyleFactory>
#include <QStatusBar>
#include <QMessageBox>
#include <QMenu>
#include <QMimeData>
#include <QDir>
#include <QClipboard>

WidgetSceneTree::WidgetSceneTree(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::WidgetSceneTree)
{
    ui->setupUi(this);
    ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    ui->treeWidget->setColumnCount(1);
    ui->treeWidget->setStyle(QStyleFactory::create("windows"));
    connect(ui->treeWidget, &QTreeWidget::itemPressed, this, &WidgetSceneTree::treeWidget_itemPressed);
    connect(ui->treeWidget, &QTreeWidget::itemDoubleClicked, this, &WidgetSceneTree::treeWidget_itemDoubleClicked);

    _contextMenu = new QMenu(this);
    _actionNew = new QAction(tr("新建"), this);
    _actionEdit = new QAction(tr("编辑"), this);
    _actionVisible = new QAction(tr("隐藏"), this);
    _actionDelete = new QAction(tr("删除"), this);
    _actionTransform = new QAction(tr("变换"), this);
    _actionMaterial = new QAction(tr("材质"), this);
    _actionPhysical = new QAction(tr("物理绑定"), this);
    _actionAttach = new QAction(tr("附加到"), this);
    _actionAnimation = new QAction(tr("动画信息"), this);
    _actionCopyName = new QAction(tr("复制名称"), this);
    QMenu* newMenu = new QMenu(this);
    newMenu->addAction(new QAction(iconNodeType("animation"), tr("骨骼动画"), this));
    newMenu->addAction(new QAction(iconNodeType("static"), tr("静态模型"), this));
    newMenu->addAction(new QAction(iconNodeType("geometry"), tr("几何体"), this));
    newMenu->addAction(new QAction(iconNodeType("skybox"), tr("天空盒"), this));
    newMenu->addAction(new QAction(iconNodeType("water"), tr("水面"), this));
    newMenu->addAction(new QAction(iconNodeType("board"), tr("广告牌"), this));
    newMenu->addAction(new QAction(iconNodeType("cloud"), tr("云层"), this));
    newMenu->addAction(new QAction(iconNodeType("screen"), tr("屏幕"), this));
    newMenu->addAction(new QAction(iconNodeType("flame"), tr("火焰"), this));
    newMenu->addAction(new QAction(iconNodeType("terrain"), tr("地形"), this));
    newMenu->addAction(new QAction(iconNodeType("text"), tr("文本"), this));
    newMenu->addAction(new QAction(iconNodeType("mirror"), tr("镜子"), this));
    newMenu->addAction(new QAction(iconNodeType("particles"), tr("粒子"), this));
    newMenu->addAction(new QAction(iconNodeType("planet"), tr("星球"), this));
    newMenu->addAction(new QAction(iconNodeType("plant"), tr("植被"), this));
    newMenu->addAction(new QAction(iconNodeType("projector"), tr("投影"), this));
    newMenu->addAction(new QAction(iconNodeType("sheet"), tr("纹理动画"), this));
    newMenu->addAction(new QAction(iconNodeType("sound"), tr("声音"), this));
    newMenu->addAction(new QAction(iconNodeType("lensflare"), tr("镜头光晕"), this));
    newMenu->addAction(new QAction(iconNodeType("axis"), tr("坐标轴"), this));
    _actionNew->setMenu(newMenu);
    const QList<QAction*> newMenuActions = newMenu->actions();
    for (qsizetype i = 0; i < newMenuActions.size(); i++) connect(newMenuActions[i], &QAction::triggered, this, &WidgetSceneTree::actionNew_triggered);
    connect(_actionEdit, &QAction::triggered, this, &WidgetSceneTree::actionEdit_triggered);
    connect(_actionVisible, &QAction::triggered, this, &WidgetSceneTree::actionVisible_triggered);
    connect(_actionDelete, &QAction::triggered, this, &WidgetSceneTree::actionDelete_triggered);
    connect(_actionTransform, &QAction::triggered, this, &WidgetSceneTree::actionOperate_triggered);
    connect(_actionMaterial, &QAction::triggered, this, &WidgetSceneTree::actionOperate_triggered);
    connect(_actionPhysical, &QAction::triggered, this, &WidgetSceneTree::actionOperate_triggered);
    connect(_actionAttach, &QAction::triggered, this, &WidgetSceneTree::actionOperate_triggered);
    connect(_actionAnimation, &QAction::triggered, this, &WidgetSceneTree::actionOperate_triggered);
    connect(_actionCopyName, &QAction::triggered, this, &WidgetSceneTree::actionOperate_triggered);
    // 扩展场景节点
    QMenu* newMenuExt = new QMenu(this);
    newMenuExt->addAction(new QAction(tr("2D瓦片"), this));
    newMenuExt->addAction(new QAction(tr("3D瓦片"), this));
    newMenuExt->addAction(new QAction(tr("地点标签"), this));
    newMenuExt->addAction(new QAction(tr("二维图表"), this));
    newMenuExt->addAction(new QAction(tr("辐射模拟"), this));
    newMenuExt->addAction(new QAction(tr("雨水"), this));
    newMenuExt->addAction(new QAction(tr("节点引用"), this));
    newMenuExt->addAction(new QAction(tr("道路"), this));
    newMenuExt->addAction(new QAction(tr("高斯溅射"), this));
    newMenuExt->addAction(new QAction(tr("分形树"), this));
    newMenuExt->addAction(new QAction(tr("水流模拟"), this));
    newMenuExt->addAction(new QAction(tr("线框模型"), this));
    _actionNewExt = new QAction(tr("扩展"), this);
    _actionNewExt->setMenu(newMenuExt);
    newMenu->addAction(_actionNewExt);
    const QList<QAction*> newMenuExtActions = newMenuExt->actions();
    for (qsizetype i = 0; i < newMenuExtActions.size(); i++) connect(newMenuExtActions[i], &QAction::triggered, this, &WidgetSceneTree::actionNew_triggered);
}

WidgetSceneTree::~WidgetSceneTree()
{
    delete ui;
}

/**
 * @brief 初始化场景树控件
 */
void WidgetSceneTree::Initialize()
{
    AvatarLibrary::avatar_register("__on_menu", handleMenu, this);
}

/**
 * @brief 重新加载场景节点
 */
void WidgetSceneTree::Reload()
{
    ui->treeWidget->clear();
    AvatarLibrary::avatar_command("scene.clear()");
    QList<std::shared_ptr<EntitySceneNode>> orderList = SceneExport::SortedSceneNode();
    for (qsizetype i = 0; i < orderList.size(); i++)
    {
        EntitySceneNode* node = orderList.at(i).get();
        AvatarLibrary::avatar_command(node->ScriptInsert());
        AvatarLibrary::avatar_command(node->ScriptTransform());
        AvatarLibrary::avatar_command(node->ScriptRenderMode());
        AvatarLibrary::avatar_command(node->ScriptMaterial());
        QList<QTreeWidgetItem*> treeParent = node->Parent == nullptr ? QList<QTreeWidgetItem*>() : ui->treeWidget->findItems(node->Parent->ToString(), Qt::MatchExactly | Qt::MatchRecursive);
        if (treeParent.isEmpty())
        {
            QTreeWidgetItem* treeItem = new QTreeWidgetItem();
            treeItem->setText(0, node->ToString());
            treeItem->setIcon(0, iconNodeType(node->Type, node->Visible));
            treeItem->setData(0, Qt::UserRole + 1, QVariant::fromValue(node));
            ui->treeWidget->addTopLevelItem(treeItem);
        }
        else
        {
            QTreeWidgetItem* treeItem = new QTreeWidgetItem(treeParent.at(0));
            treeItem->setText(0, node->ToString());
            treeItem->setIcon(0, iconNodeType(node->Type, node->Visible));
            treeItem->setData(0, Qt::UserRole + 1, QVariant::fromValue(node));
            treeItem->parent()->setExpanded(true);
        }
    }
    // 执行物理绑定和节点附加脚本
    for (qsizetype i = 0; i < orderList.size(); i++)
    {
        EntitySceneNode* node = orderList.at(i).get();
        AvatarLibrary::avatar_command(node->ScriptPhysical());
        AvatarLibrary::avatar_command(node->ExtraScript.join('\n'));
    }
}

/**
 * @brief 新增或修改场景节点
 * @param node
 */
void WidgetSceneTree::EditNode(EntitySceneNode* node)
{
    QList<QTreeWidgetItem*> treeItem = ui->treeWidget->findItems(node->ToString(), Qt::MatchExactly | Qt::MatchRecursive);
    QList<QTreeWidgetItem*> treeParentNew = node->Parent == nullptr ? QList<QTreeWidgetItem*>() : ui->treeWidget->findItems(node->Parent->ToString(), Qt::MatchExactly | Qt::MatchRecursive);
    if (!treeItem.isEmpty())
    {
        // 修改模式
        QTreeWidgetItem* target = treeItem.at(0);
        QTreeWidgetItem* parent = treeParentNew.isEmpty() ? nullptr : treeParentNew.at(0);
        // 检查父节点是否需要修改
        if (target->parent() != parent)
        {
            if (target->parent()) target->parent()->removeChild(target);
            else ui->treeWidget->takeTopLevelItem(ui->treeWidget->indexOfTopLevelItem(target));
            if (!parent) ui->treeWidget->addTopLevelItem(target);
            else
            {
                parent->addChild(target);
                parent->setExpanded(true);
            }
        }
        AvatarLibrary::avatar_command(QString("scene.delete('%1')").arg(node->Name));
    }
    else
    {
        // 新增模式
        QTreeWidgetItem* item = new QTreeWidgetItem();
        item->setText(0, node->ToString());
        item->setIcon(0, iconNodeType(node->Type));
        item->setData(0, Qt::UserRole + 1, QVariant::fromValue(node));
        if (treeParentNew.isEmpty()) ui->treeWidget->addTopLevelItem(item);
        else
        {
            treeParentNew.at(0)->addChild(item);
            treeParentNew.at(0)->setExpanded(true);
        }
    }
    AvatarLibrary::avatar_command(node->ScriptInsert());
    AvatarLibrary::avatar_command(node->ScriptTransform());
    AvatarLibrary::avatar_command(node->ScriptMaterial());
    AvatarLibrary::avatar_command(node->ScriptPhysical());
    AvatarLibrary::avatar_command(node->ScriptRenderMode());
    // 重新设置子节点的父节点
    QMapIterator<QString, std::shared_ptr<EntitySceneNode>> iter(Program::SceneNodeList);
    while (iter.hasNext())
    {
        iter.next();
        if (iter.value()->Parent == node)
        {
            AvatarLibrary::avatar_command(QString("scene.parent('%1','%2')").arg(iter.value()->Name, node->Name));
        }
    }
}

/**
 * @brief 文件拖入
 * @param event
 */
void WidgetSceneTree::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasUrls()) event->acceptProposedAction();
    else event->ignore();
}

/**
 * @brief 文件拖入释放
 * @param event
 */
void WidgetSceneTree::dropEvent(QDropEvent *event)
{
    QList<QUrl> files = event->mimeData()->urls();
    if (files.length() == 1)
    {
        QString path = files[0].toLocalFile();
        QString ext = QFileInfo(path).suffix().toUpper();
        if (QDir(path).exists() || ext == "ZIP") { Program::LoadScene(path); return; }
        else if (ext == "AVATARPROJ")
        {
            ProjectReader().Read(path);
            Program::SetupProject();
            return;
        }
    }
    QTreeWidgetItem* item = ui->treeWidget->itemAt(ui->treeWidget->viewport()->mapFrom(this, event->position().toPoint()));
    for (qsizetype i = 0; i < files.count(); i++)
    {
        QString path = files[i].toLocalFile();
        QFileInfo fileInfo(path);
        QString ext = fileInfo.suffix().toUpper();
        QString name = fileInfo.completeBaseName();
        QString filepath = path.replace('\\', '/');
        const QStringList staticExt = QStringList({"STL", "OBJ", "3DS", "B3DM", "I3DM"});
        const QStringList animationExt = QStringList({"MS3D", "BVH", "DAE", "GLB", "GLTF", "VRM"});
        const QStringList videoExt = QStringList({"MP4", "AVI", "FLV", "MKV"});
        const QStringList imageExt = QStringList({"JPG", "PNG", "BMP", "TGA"});
        if (ext == "LUA") AvatarLibrary::avatar_command(QString("engine.script('%1')").arg(filepath));
        else if (staticExt.contains(ext)) insertNode(item, std::make_shared<EntitySceneNode>(nullptr, "static", name, QString("meshFile='%1'").arg(filepath)));
        else if (animationExt.contains(ext)) insertNode(item, std::make_shared<EntitySceneNode>(nullptr, "animation", name, QString("meshFile='%1'").arg(filepath)));
        else if (videoExt.contains(ext)) insertNode(item, std::make_shared<EntitySceneNode>(nullptr, "board", name, QString("width=4,height=3,texture='%1'").arg(filepath)));
        else if (imageExt.contains(ext))
        {
            QSize size = Program::MainWin->GetViewSize();
            std::shared_ptr<EntitySceneNode> node = std::make_shared<EntitySceneNode>(nullptr, "screen", name, QString("width=-1,height=-1,texture='%1'").arg(filepath));
            node->Position.setX(size.width() / 2);
            node->Position.setY(size.height() / 2);
            insertNode(item, node);
        }
    }
}

/**
 * @brief 右键菜单
 * @param event
 */
void WidgetSceneTree::on_treeWidget_customContextMenuRequested(const QPoint &pos)
{
    QTreeWidgetItem* item = ui->treeWidget->itemAt(pos);
    _contextMenu->clear();
    _contextMenu->addAction(_actionNew);
    if (item != nullptr)
    {
        EntitySceneNode* node = item->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
        _actionVisible->setText(node->Visible ? "隐藏" : "显示");
        _contextMenu->addAction(_actionEdit);
        _contextMenu->addAction(_actionVisible);
        _contextMenu->addAction(_actionDelete);
        _contextMenu->addAction(_actionTransform);
        _contextMenu->addAction(_actionMaterial);
        _contextMenu->addAction(_actionPhysical);
        _contextMenu->addAction(_actionAttach);
        if (node->Type == "animation") _contextMenu->addAction(_actionAnimation);
        _contextMenu->addAction(_actionCopyName);
    }
    _actionNewExt->setVisible(Program::Config.PluginUsed.contains("avatar_extra_scenenode"));
    ui->treeWidget->setCurrentItem(item);
    _contextMenu->exec(QCursor::pos());
}

/**
 * @brief 鼠标点击节点
 * @param item
 */
void WidgetSceneTree::treeWidget_itemPressed(QTreeWidgetItem *item)
{
    if(qApp->mouseButtons() == Qt::LeftButton)
    {
        EntitySceneNode* node = item->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
        emit sig_selectNode(node->Name);
    }
}

/**
 * @brief 场景节点双击
 * @param item
 */
void WidgetSceneTree::treeWidget_itemDoubleClicked(QTreeWidgetItem *item)
{
    EntitySceneNode* node = item->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
    AvatarLibrary::avatar_command(QString("setCameraTarget('%1')").arg(node->Name));
}

/**
 * @brief 新建场景节点
 */
void WidgetSceneTree::actionNew_triggered()
{
    EntitySceneNode* parent = nullptr;
    QTreeWidgetItem* item = ui->treeWidget->currentItem();
    if (item) parent = item->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
    QAction* action = qobject_cast<QAction*>(sender());
    QString text = action->text();
    if (text == "骨骼动画") emit sig_createNode("animation", parent);
    else if (text == "静态模型") emit sig_createNode("static", parent);
    else if (text == "几何体") emit sig_createNode("geometry", parent);
    else if (text == "天空盒") emit sig_createNode("skybox", parent);
    else if (text == "水面") emit sig_createNode("water", parent);
    else if (text == "广告牌") emit sig_createNode("board", parent);
    else if (text == "云层") emit sig_createNode("cloud", parent);
    else if (text == "屏幕") emit sig_createNode("screen", parent);
    else if (text == "火焰") emit sig_createNode("flame", parent);
    else if (text == "地形") emit sig_createNode("terrain", parent);
    else if (text == "文本") emit sig_createNode("text", parent);
    else if (text == "镜子") emit sig_createNode("mirror", parent);
    else if (text == "粒子") emit sig_createNode("particles", parent);
    else if (text == "星球") emit sig_createNode("planet", parent);
    else if (text == "植被") emit sig_createNode("plant", parent);
    else if (text == "投影") emit sig_createNode("projector", parent);
    else if (text == "纹理动画") emit sig_createNode("sheet", parent);
    else if (text == "声音") emit sig_createNode("sound", parent);
    else if (text == "镜头光晕") emit sig_createNode("lensflare", parent);
    else if (text == "坐标轴") emit sig_createNode("axis", parent);
    // 扩展场景节点
    else if (text == "2D瓦片") emit sig_createNode("2dtiles", parent);
    else if (text == "3D瓦片") emit sig_createNode("3dtiles", parent);
    else if (text == "地点标签") emit sig_createNode("placemark", parent);
    else if (text == "二维图表") emit sig_createNode("plot", parent);
    else if (text == "辐射模拟") emit sig_createNode("radiation", parent);
    else if (text == "雨水") emit sig_createNode("rain", parent);
    else if (text == "节点引用") emit sig_createNode("reference", parent);
    else if (text == "道路") emit sig_createNode("route", parent);
    else if (text == "高斯溅射") emit sig_createNode("splatting", parent);
    else if (text == "分形树") emit sig_createNode("tree", parent);
    else if (text == "水流模拟") emit sig_createNode("waterflow", parent);
    else if (text == "线框模型") emit sig_createNode("wireframe", parent);
}

/**
 * @brief 编辑场景节点
 */
void WidgetSceneTree::actionEdit_triggered()
{
    QTreeWidgetItem* item = ui->treeWidget->currentItem();
    if (item)
    {
        EntitySceneNode* node = item->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
        emit sig_editNode(node->Name);
    }
}

/**
 * @brief 隐藏显示场景节点
 */
void WidgetSceneTree::actionVisible_triggered()
{
    QTreeWidgetItem* item = ui->treeWidget->currentItem();
    if (item)
    {
        EntitySceneNode* node = item->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
        node->Visible = !node->Visible;
        item->setIcon(0, iconNodeType(node->Type, node->Visible));
        AvatarLibrary::avatar_command(QString("scene.visible('%1',%2)").arg(node->Name, node->Visible ? "true" : "false"));
    }
}

/**
 * @brief 删除场景节点
 */
void WidgetSceneTree::actionDelete_triggered()
{
    QTreeWidgetItem* item = ui->treeWidget->currentItem();
    if (item && QMessageBox::question(this, "提示", "确实要删除吗?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
    {
        deleteNode(item);
    }
}

/**
 * @brief 场景节点操作
 */
void WidgetSceneTree::actionOperate_triggered()
{
    QAction* action = (QAction*)sender();
    QTreeWidgetItem* item = ui->treeWidget->currentItem();
    if (item)
    {
        EntitySceneNode* node = item->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
        if (action == _actionTransform) emit sig_nodeTransform(node->Name);
        else if (action == _actionMaterial) emit sig_nodeMaterial(node->Name);
        else if (action == _actionPhysical) emit sig_nodePhysical(node->Name);
        else if (action == _actionAttach) emit sig_nodeAttachment(node->Name);
        else if (action == _actionAnimation) emit sig_nodeAnimation(node->Name);
        else if (action == _actionCopyName) QApplication::clipboard()->setText(node->Name);
    }
}

/**
 * @brief 添加场景节点
 * @param item
 * @param sceneNode
 */
void WidgetSceneTree::insertNode(QTreeWidgetItem* item, std::shared_ptr<EntitySceneNode> sceneNode)
{
    if (Program::SceneNodeList.count(sceneNode->Name) > 0)
    {
        QMessageBox::warning(this, "错误", QString("已存在名称为 '%1' 的节点").arg(sceneNode->Name));
        return;
    }
    sceneNode->Parent = item == nullptr ? nullptr : item->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
    Program::SceneNodeList.insert(sceneNode->Name, sceneNode);
    EntitySceneNode* node = sceneNode.get();
    AvatarLibrary::avatar_command(node->ScriptInsert());
    AvatarLibrary::avatar_command(node->ScriptTransform());
    AvatarLibrary::avatar_command(node->ScriptMaterial());
    if (item)
    {
        QTreeWidgetItem* treeItem = new QTreeWidgetItem(item);
        treeItem->setText(0, node->ToString());
        treeItem->setIcon(0, iconNodeType(node->Type));
        treeItem->setData(0, Qt::UserRole + 1, QVariant::fromValue(node));
        item->setExpanded(true);
    }
    else
    {
        QTreeWidgetItem* treeItem = new QTreeWidgetItem();
        treeItem->setText(0, node->ToString());
        treeItem->setIcon(0, iconNodeType(node->Type));
        treeItem->setData(0, Qt::UserRole + 1, QVariant::fromValue(node));
        ui->treeWidget->addTopLevelItem(treeItem);
    }
}

/**
 * @brief 移除场景节点
 * @param item
 */
void WidgetSceneTree::deleteNode(QTreeWidgetItem* item)
{
    EntitySceneNode* node = item->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
    QTreeWidgetItem* parentItem = item->parent();
    EntitySceneNode* parentNode = parentItem == nullptr ? nullptr : parentItem->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
    while (item->childCount() > 0)
    {
        QTreeWidgetItem* childItem = item->child(0);
        item->removeChild(childItem);
        if (parentItem) parentItem->addChild(childItem);
        else ui->treeWidget->addTopLevelItem(childItem);
        EntitySceneNode* childNode = childItem->data(0, Qt::UserRole + 1).value<EntitySceneNode*>();
        childNode->Parent = parentNode;
    }
    AvatarLibrary::avatar_command(QString("scene.delete('%1')").arg(node->Name));
    Program::SceneNodeList.remove(node->Name);
    delete item;
}

/**
 * @brief 获取代表节点类型的图标
 * @param type
 * @param visible
 * @return
 */
QIcon WidgetSceneTree::iconNodeType(const QString& type, bool visible)
{
    const QString resource = QString(":/resource/icon/scenetree/%2_%1.png").arg(visible ? "normal" : "hide");
    return QIcon(resource.arg(type));
}

/**
 * @brief 处理场景右键菜单
 * @param params
 * @param widgetSceneTree
 * @return
 */
int WidgetSceneTree::handleMenu(int, const char **params, void *widgetSceneTree)
{
    QString action = params[0];
    QString node = params[1];
    WidgetSceneTree* sceneTree = static_cast<WidgetSceneTree*>(widgetSceneTree);
    QList<QTreeWidgetItem*> treeItem = sceneTree->ui->treeWidget->findItems(node, Qt::MatchExactly | Qt::MatchRecursive);
    if (treeItem.isEmpty()) return 0;
    sceneTree->ui->treeWidget->setCurrentItem(treeItem.at(0));
    if (action == "edit") emit sceneTree->_actionEdit->triggered();
    else if (action == "visible") emit sceneTree->_actionVisible->triggered();
    else if (action == "delete") emit sceneTree->_actionDelete->triggered();
    else if (action == "transform") emit sceneTree->_actionTransform->triggered();
    else if (action == "attach") emit sceneTree->_actionAttach->triggered();
    else if (action == "animation") emit sceneTree->_actionAnimation->triggered();
    else if (action == "copyName") emit sceneTree->_actionCopyName->triggered();
    else return 0;
    return 1;
}
